﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using ContosoUniversity.SchoolViewModels;

namespace ContosoUniversity.Controllers
{
    public class InstructorsController : Controller
    {
        private readonly SchoolContext _context;

        public InstructorsController(SchoolContext context)
        {
            _context = context;
        }

        // GET: Instructors
        public async Task<IActionResult> Index(int? id, int? courseID)
        {

            var viewModel = new InstructorIndexData();
            viewModel.Instructors = await _context.Instructors
                                        .Include(t => t.OfficeAssignment)
                                        .Include(t => t.CourseAssignments)
                                            .ThenInclude(t => t.Course)
                                            .ThenInclude(t => t.Department)
                                        .Include(t => t.CourseAssignments)
                                            .ThenInclude(t => t.Course)
                                                .ThenInclude(t => t.Enrollments)
                                                    .ThenInclude(t => t.Student)
                                        .OrderBy(t => t.LastName)
                                        .AsNoTracking()
                                        .ToListAsync();

            if (id != null)
            {
                ViewData["InstructorID"] = id.Value;
                Instructor instructor = viewModel.Instructors.Single(i => i.ID == id.Value);
                viewModel.Courses = instructor.CourseAssignments.Select(s => s.Course);
            }

            if (courseID != null)
            {
                ViewData["CourseID"] = courseID.Value;
                viewModel.Enrollments = viewModel.Courses.Where(x => x.CourseID == courseID).Single().Enrollments;
            }

            return View(viewModel);
        }

        // GET: Instructors/Details/5
        public async Task<IActionResult> Details(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var instructor = await _context.Instructors
                .SingleOrDefaultAsync(m => m.ID == id);
            if (instructor == null)
            {
                return NotFound();
            }

            return View(instructor);
        }

        // GET: Instructors/Create
        public IActionResult Create()
        {
            var instructor = new Instructor();
            instructor.CourseAssignments = new List<CourseAssignment>();
            PopulateAssignedCourseData(instructor);

            return View();
        }

        // POST: Instructors/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("LastName,FirstMidName,HireDate,OfficeAssignment")] Instructor instructor, string[] selectedCourses)
        {
            if (selectedCourses != null)
            {
                instructor.CourseAssignments = new List<CourseAssignment>();
                foreach (var course in selectedCourses)
                {
                    instructor.CourseAssignments.Add(new CourseAssignment
                    {
                        CourseID = Convert.ToInt32(course),
                        InstructorID = instructor.ID
                    });
                }
            }

            if (ModelState.IsValid)
            {
                _context.Add(instructor);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(instructor);
        }

        // GET: Instructors/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var instructor = await _context.Instructors
                                    .Include(t => t.OfficeAssignment)
                                    .Include(t => t.CourseAssignments).ThenInclude(t => t.Course)
                                    .AsNoTracking().SingleOrDefaultAsync(m => m.ID == id);
            if (instructor == null)
            {
                return NotFound();
            }
            PopulateAssignedCourseData(instructor);
            return View(instructor);
        }

        private void PopulateAssignedCourseData(Instructor instructor)
        {
            var allCourses = _context.Courses;
            var inStructorCourses = new HashSet<int>(instructor.CourseAssignments.Select(t => t.CourseID));
            var viewModel = new List<AssignedCourseData>();
            foreach (var item in allCourses)
            {
                viewModel.Add(new AssignedCourseData()
                {
                    CourseID = item.CourseID,
                    Title = item.Title,
                    Assigned = inStructorCourses.Contains(item.CourseID)
                });
            }
            ViewData["Courses"] = viewModel;
        }

        // POST: Instructors/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost, ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> EditPost(int? id, string[] selectedCourses)
        {
            if (id == null)
            {
                return NotFound();
            }
            var instructor = await _context.Instructors
                                    .Include(t => t.OfficeAssignment)
                                    .Include(t => t.CourseAssignments)
                                        .ThenInclude(t => t.Course)
                                    .SingleOrDefaultAsync(t => t.ID == id);
            if (await TryUpdateModelAsync<Instructor>(instructor, "", t => t.FirstMidName, t => t.LastName, t => t.HireDate, t => t.OfficeAssignment))
            {
                if (string.IsNullOrWhiteSpace(instructor.OfficeAssignment?.Location))
                {
                    instructor.OfficeAssignment = null;
                }
                UpdateInstructorCourses(selectedCourses, instructor);
                try
                {
                    await _context.SaveChangesAsync();
                }
                catch (Exception)
                {
                    ModelState.AddModelError("", "Unable to save changes");
                }
                return RedirectToAction(nameof(Index));
            }

            PopulateAssignedCourseData(instructor);
            return View(instructor);
        }

        private void UpdateInstructorCourses(string[] seletedCourses, Instructor instructor)
        {
            if (seletedCourses == null)
            {
                instructor.CourseAssignments = new List<CourseAssignment>();
                return;
            }
            //前台选择的课程
            var selectedCoursesHS = new HashSet<string>(seletedCourses);
            //已存在的
            var instructorCourses = new HashSet<int>(instructor.CourseAssignments.Select(t => t.CourseID));
            foreach (var course in _context.Courses)
            {
                //前台选择的
                if (selectedCoursesHS.Contains(course.CourseID.ToString()))
                {
                    //不包含在已选的
                    if (!instructorCourses.Contains(course.CourseID))
                    {
                        instructor.CourseAssignments.Add(new CourseAssignment()
                        {
                            InstructorID = instructor.ID,
                            CourseID = course.CourseID
                        });
                    }
                }
                else
                {
                    if (instructorCourses.Contains(course.CourseID))
                    {
                        var courseAssignment = instructor.CourseAssignments.SingleOrDefault(t => t.CourseID == course.CourseID);
                        instructor.CourseAssignments.Remove(courseAssignment);
                    }
                }
            }
        }



        // GET: Instructors/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var instructor = await _context.Instructors
                .SingleOrDefaultAsync(m => m.ID == id);
            if (instructor == null)
            {
                return NotFound();
            }

            return View(instructor);
        }

        // POST: Instructors/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(int id)
        {
            var instructor = await _context.Instructors
                                           .Include(t => t.CourseAssignments)
                                           .SingleOrDefaultAsync(m => m.ID == id);
            var departments = await _context.Departments.Where(t => t.InstructorID == instructor.ID).AsNoTracking().ToListAsync();
            departments.ForEach(t => t.Administrator = null);

            _context.Instructors.Remove(instructor);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool InstructorExists(int id)
        {
            return _context.Instructors.Any(e => e.ID == id);
        }
    }
}
